package com.sinszm.wx.pay;

import com.sinszm.common.exception.ApiException;
import com.sinszm.common.util.CommonUtils;
import com.sinszm.wx.pay.req.*;
import com.sinszm.wx.pay.resp.*;
import com.sinszm.wx.pay.support.WXPay;
import com.sinszm.wx.pay.support.WXPayConfig;
import com.sinszm.wx.pay.support.WXPayConstants;
import com.sinszm.wx.pay.support.WXPayUtil;
import org.apache.commons.io.IOUtils;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.Map;

import static com.sinszm.wx.exception.WxApiError.*;

/**
 * 支付服务
 *
 * @author chenjianbo
 */
@Component
public class PayService {

    @Resource
    private WXPay wxPay;

    /**
     * 退款通知中的加密串KEY
     */
    private static final String REQ_INFO = "req_info";

    /**
     * 签名密钥的MD5码
     */
    private static final String KEY_MD5 = "key_md5";

    /**
     * 获取签名类型
     * @return  目标签名类型
     */
    public WXPayConstants.SignType getSignType() {
        return wxPay.getSignType();
    }

    /**
     * 获取支付配置
     * @return  公共配置信息
     */
    public WXPayConfig getConfig() {
        return wxPay.getConfig();
    }

    /**
     * 未解析方法可调用入口
     *
     * @return  微信支付
     */
    public WXPay wxpay(){
        return wxPay;
    }

    /**
     * 支付/退款结果通知接收
     * @param request   请求上下文
     * @return          结果
     */
    public NoticeInfoResp responseNotifyData(HttpServletRequest request) {
        try {
            String xmlStr = IOUtils.toString(request.getInputStream(), request.getCharacterEncoding());
            Map<String, String> response = WXPayUtil.xmlToMap(xmlStr);
            if (response.containsKey(REQ_INFO)) {
                response.put(KEY_MD5, CommonUtils.MD5(getConfig().getKey()));
                NoticeInfoResp resp = PayDataFormat.respData(response, NoticeInfoResp.class);
                resp.setNoticeType(NoticeInfoResp.NoticeType.REFUND);
                return resp;
            }
            if (wxPay.isPayResultNotifySignatureValid(response)) {
                NoticeInfoResp resp = PayDataFormat.respData(response, NoticeInfoResp.class);
                resp.setNoticeType(NoticeInfoResp.NoticeType.PAY);
                return resp;
            }
            throw new ApiException(WX_PAY_ERROR_07);
        } catch (Exception e) {
            if (e instanceof ApiException) {
                throw (ApiException)e;
            } else {
                throw new ApiException(WX_PAY_ERROR_08);
            }
        }
    }

    /**
     * 预约下单
     * @param unifiedOrder  参数
     * @return  结果
     */
    public UnifiedOrderResp unifiedOrder(UnifiedOrder unifiedOrder) {
        try {
            return PayDataFormat.respData(
                    wxPay.unifiedOrder(PayDataFormat.reqData(unifiedOrder)),
                    UnifiedOrderResp.class
            );
        } catch (Exception e) {
            throw new ApiException(WX_PAY_ERROR_01);
        }
    }

    /**
     * 订单查询
     * @param orderQuery    参数
     * @return 结果
     */
    public OrderQueryResp orderQuery(OrderQuery orderQuery) {
        try {
            return PayDataFormat.respData(
                    wxPay.orderQuery(PayDataFormat.reqData(orderQuery)),
                    OrderQueryResp.class
            );
        } catch (Exception e) {
            throw new ApiException(WX_PAY_ERROR_02);
        }
    }

    /**
     * 关闭订单
     * @param closeOrder    参数
     * @return 结果
     */
    public CloseOrderResp closeOrder(CloseOrder closeOrder) {
        try {
            return PayDataFormat.respData(
                    wxPay.closeOrder(PayDataFormat.reqData(closeOrder)),
                    CloseOrderResp.class
            );
        } catch (Exception e) {
            throw new ApiException(WX_PAY_ERROR_03);
        }
    }

    /**
     * 申请退款
     * @param refundOrder   参数
     * @return 结果
     */
    public RefundOrderResp refund(RefundOrder refundOrder) {
        try {
            return PayDataFormat.respData(
                    wxPay.refund(PayDataFormat.reqData(refundOrder)),
                    RefundOrderResp.class
            );
        } catch (Exception e) {
            throw new ApiException(WX_PAY_ERROR_04);
        }
    }

    /**
     * 退款查询
     * @param refundQuery   参数
     * @return 结果
     */
    public OrderRefundQueryResp refundQuery(OrderRefundQuery refundQuery) {
        try {
            return PayDataFormat.respData(
                    wxPay.refundQuery(PayDataFormat.reqData(refundQuery)),
                    OrderRefundQueryResp.class
            );
        } catch (Exception e) {
            throw new ApiException(WX_PAY_ERROR_05);
        }
    }

    /**
     * 对账
     * @param billOrder 参数
     * @return 结果
     */
    public BillOrderResp downloadBill(BillOrder billOrder) {
        try {
            return PayDataFormat.respData(
                    wxPay.downloadBill(PayDataFormat.reqData(billOrder)),
                    BillOrderResp.class
            );
        } catch (Exception e) {
            throw new ApiException(WX_PAY_ERROR_06);
        }
    }

}
